home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / WASTE 1.2 / WASTE Demo ƒ / WEDemoMenus.c < prev    next >
Text File  |  1996-06-20  |  21KB  |  991 lines

  1. /*
  2.     WASTE Demo Project:
  3.     Menu Handling
  4.  
  5.     Copyright © 1993-1996 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11. #ifndef __ALIASES__
  12. #include <Aliases.h>
  13. #endif
  14.  
  15. #ifndef __DEVICES__
  16. #include <Devices.h>
  17. #endif
  18.  
  19. #ifndef __LOWMEM__
  20. #include <LowMem.h>
  21. #endif
  22.  
  23. #ifndef __STANDARDFILE__
  24. #include <StandardFile.h>
  25. #endif
  26.  
  27. #ifndef __FILETYPESANDCREATORS__
  28. #include <FileTypesAndCreators.h>
  29. #endif
  30.  
  31. #ifndef __TOOLUTILS__
  32. #include <ToolUtils.h>
  33. #endif
  34.  
  35. #ifndef __WEDEMOAPP__
  36. #include "WEDemoIntf.h"
  37. #endif
  38.  
  39. #include "WETabs.h"
  40.  
  41. // resource types
  42.  
  43. #define kTypeMenuColorTable        'mctb'
  44.  
  45. // static variables
  46.  
  47. static MenuCRsrcHandle        sColors;        // handle to the 'mctb' resource for the Color menu
  48.  
  49. // constants used by DoClose()
  50.  
  51. enum {
  52.     kButtonSave            = 1,
  53.     kButtonCancel,
  54.     kButtonDontSave
  55. };
  56.  
  57. void SetDefaultDirectory( const FSSpec *spec )
  58. {
  59.     LMSetCurDirStore( spec->parID );
  60.     LMSetSFSaveDisk( -spec->vRefNum );
  61. }
  62.  
  63. static pascal Boolean MySFDialogFilter( DialogRef dialog, EventRecord *event, short *item, void *yourData )
  64. {
  65. #pragma unused ( item, yourData )
  66.  
  67.     //     intercept window events directed to windows behind the dialog
  68.     if ( ( event->what == updateEvt ) || ( event->what == activateEvt ) )
  69.     {
  70.         if ( (WindowRef) event->message != GetDialogWindow( dialog ) )
  71.         {
  72.             DoWindowEvent( event );
  73.         }
  74.     }
  75.  
  76.     return false;
  77. }
  78.  
  79. static ModalFilterYDUPP GetMySFDialogFilter( void )
  80. {
  81. #ifdef __cplusplus
  82.     static ModalFilterYDUPP sFilterUPP = NewModalFilterYDProc( MySFDialogFilter );
  83. #else
  84.     static ModalFilterYDUPP sFilterUPP = nil;
  85.     if ( sFilterUPP == nil )
  86.     {
  87.         sFilterUPP = NewModalFilterYDProc( MySFDialogFilter );
  88.     }
  89. #endif
  90.  
  91.     return sFilterUPP;
  92. }
  93.  
  94. short    FindMenuItemText( MenuRef menu, ConstStr255Param stringToFind )
  95. {
  96.     short        item;
  97.     Str255        itemString;
  98.  
  99.     for ( item = CountMItems( menu ); item >= 1; item-- )
  100.     {
  101.         GetMenuItemText( menu, item, itemString );
  102.         if ( EqualString( itemString, stringToFind, false, false ) )
  103.             break;
  104.     }
  105.  
  106.     return item;
  107. }
  108.  
  109. Boolean    EqualColor( const RGBColor *rgb1, const RGBColor *rgb2 )
  110. {
  111.     return ( (rgb1->red == rgb2->red) && (rgb1->green == rgb2->green) && (rgb1->blue == rgb2->blue) );
  112. }
  113.  
  114.  
  115. void    PrepareMenus( void )
  116. {
  117.     WindowRef        window;
  118.     WEReference        we;
  119.     MenuRef            menu;
  120.     short            item;
  121.     Str255            itemText;
  122.     long            selStart, selEnd;
  123.     WEActionKind    actionKind;
  124.     WEStyleMode        mode;
  125.     TextStyle        ts;
  126.     Boolean            temp;
  127.  
  128.     // get a pointer to the frontmost window, if any
  129.  
  130.     window = FrontWindow();
  131.  
  132.     // get associated WE instance
  133.  
  134.     we = (window != nil) ? GetWindowWE(window) : nil;
  135.  
  136.     // *** FILE MENU ***
  137.  
  138.     menu = GetMenuHandle( kMenuFile );
  139.  
  140.     // first disable all items
  141.  
  142.     for ( item = CountMItems( menu); item >= 1; item-- )
  143.         DisableItem( menu, item );
  144.  
  145.     // New, Open, and Quit are always enabled
  146.  
  147.     EnableItem( menu, kItemNew );
  148.     EnableItem( menu, kItemOpen );
  149.     EnableItem( menu, kItemQuit );
  150.  
  151.     // enable Close and Save As if there is an active window
  152.  
  153.     if ( window != nil )
  154.     {
  155.         EnableItem( menu, kItemClose );
  156.         EnableItem( menu, kItemSaveAs );
  157.  
  158.         // enable Save is the active window is dirty
  159.  
  160.         if ( WEGetModCount( we ) > 0 )
  161.             EnableItem( menu, kItemSave );
  162.     }
  163.  
  164.     // *** EDIT MENU ***
  165.  
  166.     menu = GetMenuHandle( kMenuEdit );
  167.  
  168.     // first, disable all items
  169.  
  170.     for ( item = CountMItems( menu ); item >= 1; item-- )
  171.         DisableItem( menu, item );
  172.  
  173.     // by default, the Undo menu item should read "Can't Undo"
  174.  
  175.     GetIndString( itemText, kUndoStringsID, 1 );
  176.     SetMenuItemText( menu, kItemUndo, itemText );
  177.  
  178.     if ( window != nil )
  179.     {
  180.         // enable Paste if there's anything pasteable on the Clipboard
  181.  
  182.         if ( WECanPaste( we ) )
  183.             EnableItem( menu, kItemPaste );
  184.  
  185.         // enable Undo if anything can be undone
  186.  
  187.         actionKind = WEGetUndoInfo( &temp, we );
  188.  
  189.         if ( actionKind != weAKNone )
  190.         {
  191.             EnableItem( menu, kItemUndo );
  192.  
  193.             // change the Undo menu item to "Undo/Redo" + name of action to undo/redo
  194.  
  195.             GetIndString( itemText, kUndoStringsID, 2 * actionKind + temp );
  196.             SetMenuItemText( menu, kItemUndo, itemText );
  197.         }
  198.  
  199.         // enable Select All if there is anything to select
  200.  
  201.         if ( WEGetTextLength( we ) > 0 )
  202.             EnableItem( menu, kItemSelectAll );
  203.  
  204.         // get the current selection range
  205.  
  206.         WEGetSelection( &selStart, &selEnd, we );
  207.         if ( selStart != selEnd )
  208.         {
  209.             // enable Cut, Copy, and Clear if the selection range is not empty
  210.  
  211.             EnableItem( menu, kItemCut );
  212.             EnableItem( menu, kItemCopy );
  213.             EnableItem( menu, kItemClear );
  214.         }
  215.  
  216.         // determine which style attributes are continuous over the current selection range
  217.         // we'll need this information in order to check the Font/Size/Style/Color menus properly
  218.  
  219.         mode = weDoAll;  // query about all attributes
  220.         temp = WEContinuousStyle( &mode, &ts, we );
  221.  
  222.     }
  223.     else
  224.         mode = 0;  // no window, so check no items
  225.  
  226.     // *** FONT MENU ***
  227.  
  228.     menu = GetMenuHandle( kMenuFont );
  229.  
  230.     // first, remove all check marks
  231.  
  232.     for ( item = CountMItems( menu ); item >= 1; item-- )
  233.         CheckItem( menu, item, false );
  234.  
  235.     // if there is a continuous font all over the selection range, check the
  236.     // corresponding menu item
  237.  
  238.     if ( mode & weDoFont )
  239.     {
  240.         GetFontName( ts.tsFont, itemText );
  241.         CheckItem( menu, FindMenuItemText( menu, itemText ), true );
  242.     }
  243.  
  244.     // *** SIZE MENU ***
  245.  
  246.     menu = GetMenuHandle( kMenuSize );
  247.  
  248.     // first, remove all check marks
  249.  
  250.     for ( item = CountMItems( menu ); item >= 1; item-- )
  251.         CheckItem( menu, item, false );
  252.  
  253.     // if there is a continuous font size all over the selection range
  254.     // check the corresponding menu item
  255.  
  256.     if ( mode & weDoSize )
  257.     {
  258.         NumToString( ts.tsSize, itemText );
  259.         CheckItem( menu, FindMenuItemText( menu, itemText ), true );
  260.     }
  261.  
  262.     // *** STYLE MENU ***
  263.  
  264.     menu = GetMenuHandle( kMenuStyle );
  265.  
  266.     // first, remove all check marks
  267.     for ( item = CountMItems( menu ); item >= 1; item-- )
  268.         CheckItem( menu, item, false );
  269.  
  270.     // check the style menu items corresponding to style attributes
  271.     if ( mode & weDoFace )
  272.     {
  273.         if ( ts.tsFace == normal )
  274.         {
  275.             CheckItem( menu, kItemPlainText, true );
  276.         }
  277.  
  278.         for ( item = kItemBold; item <= kItemExtended; item++ )
  279.         {
  280.             if (ts.tsFace & ( 1 << ( item - kItemBold ) ) )
  281.             {
  282.                 CheckItem( menu, item, true );
  283.             }
  284.         }
  285.     }
  286.  
  287.     // *** COLOR MENU ***
  288.  
  289.     menu = GetMenuHandle( kMenuColor );
  290.  
  291.     // first, remove all check marks
  292.  
  293.     for ( item = CountMItems( menu ); item >= 1; item-- )
  294.         CheckItem( menu, item, false );
  295.  
  296.     // if there is a continuous color all over the selection range,
  297.     // check the corresponding menu item (if any )
  298.  
  299.     if ( mode & weDoColor )
  300.     {
  301.         for ( item = (*sColors)->numEntries - 1; item >= 0; item-- )
  302.         {
  303.             if ( EqualColor( &ts.tsColor, & (*sColors)->mcEntryRecs[item].mctRGB2 ) )
  304.             {
  305.                 CheckItem( menu, (*sColors)->mcEntryRecs[item].mctItem, true );
  306.             }
  307.  
  308.         } // end for loop
  309.     }
  310.  
  311.     // *** FEATURES MENU ***
  312.  
  313.     menu = GetMenuHandle( kMenuFeatures );
  314.  
  315.     // first remove all check marks (except the first item, which has a submenu!!)
  316.  
  317.     for ( item = CountMItems( menu ); item >= 2; item-- )
  318.         CheckItem( menu, item, false );
  319.  
  320.     if ( window != nil )
  321.     {
  322.         // mark each item according to the corresponding feature
  323.  
  324.         if ( WEIsTabHooks( we ) )
  325.         {
  326.             CheckItem( menu, kItemTabHooks, true );
  327.             DisableItem( menu, kItemAlignment );
  328.         }
  329.         else
  330.             EnableItem( menu, kItemAlignment );
  331.  
  332.         if ( WEFeatureFlag( weFAutoScroll, weBitTest, we ) )
  333.             CheckItem( menu, kItemAutoScroll, true );
  334.  
  335.         if ( WEFeatureFlag( weFOutlineHilite, weBitTest, we ))
  336.             CheckItem( menu, kItemOutlineHilite, true );
  337.  
  338.         if ( WEFeatureFlag( weFReadOnly, weBitTest, we ))
  339.             CheckItem( menu, kItemReadOnly, true );
  340.  
  341.         if ( WEFeatureFlag( weFIntCutAndPaste, weBitTest, we ))
  342.             CheckItem( menu, kItemIntCutAndPaste, true );
  343.  
  344.         if ( WEFeatureFlag( weFDragAndDrop, weBitTest, we ))
  345.             CheckItem( menu, kItemDragAndDrop, true );
  346.  
  347.         if ( WEFeatureFlag( weFDrawOffscreen, weBitTest, we ) )
  348.             CheckItem( menu, kItemOffscreenDrawing, true );
  349.     }
  350.  
  351.     // *** ALIGNMENT MENU ***
  352.  
  353.     menu = GetMenuHandle( kMenuAlignment );
  354.  
  355.     // first, remove all check marks
  356.     for ( item = CountMItems( menu ); item >= 1; item-- )
  357.         CheckItem( menu, item, false );
  358.  
  359.     if ( window != nil )
  360.     {
  361.         // find the Aligment menu item corresponding to mthe current alignment state
  362.         switch ( WEGetAlignment( we ) )
  363.         {
  364.             case weFlushLeft:
  365.                 item = kItemAlignLeft;
  366.                 break;
  367.  
  368.             case weFlushRight:
  369.                 item = kItemAlignRight;
  370.                 break;
  371.  
  372.             case weFlushDefault:
  373.                 item = kItemAlignDefault;
  374.                 break;
  375.  
  376.             case weCenter:
  377.                 item = kItemCenter;
  378.                 break;
  379.  
  380.             case weJustify:
  381.                 item = kItemJustify;
  382.                 break;
  383.         }
  384.  
  385.         // check the menu item
  386.         CheckItem( menu, item, true );
  387.     }
  388. }
  389.  
  390. void DoDeskAcc( short menuItem )
  391. {
  392.     Str255 deskAccessoryName;
  393.  
  394.     GetMenuItemText( GetMenuHandle( kMenuApple ), menuItem, deskAccessoryName );
  395.     OpenDeskAcc( deskAccessoryName );
  396. }
  397.  
  398. OSErr DoNew( void )
  399. {
  400.     // create a new window from scratch
  401.     return CreateWindow( nil );
  402. }
  403.  
  404. OSErr DoOpen( void )
  405. {
  406.     StandardFileReply        reply;
  407.     SFTypeList                typeList;
  408.     OSErr                    err = noErr;
  409.     Point                    where = { -1, -1 };  // auto center dialog
  410.  
  411.     // set up a list of file types we can open for StandardGetFile
  412.     typeList[0] = kTypeText;
  413.     typeList[1] = ftSimpleTextDocument;
  414.  
  415.     // put up the standard open dialog box.
  416.     // (we use CustomGetFile instead of StandardGetFile because we want to provide
  417.     // our own dialog filter procedure that takes care of updating our windows)
  418.     CustomGetFile( nil, 2, typeList, &reply, 0, where, nil, GetMySFDialogFilter( ), nil, nil, nil );
  419.  
  420.     // if the user ok'ed the dialog, create a new window from the specified file
  421.     if ( reply.sfGood )
  422.         err = CreateWindow( &reply.sfFile );
  423.     else
  424.         err = userCanceledErr;
  425.  
  426.     return err;
  427. }
  428.  
  429. OSErr SaveWindow( const FSSpec *pFileSpec, WindowRef window )
  430. {
  431.     DocumentHandle    hDocument;
  432.     AliasHandle        alias = nil;
  433.     OSErr            err;
  434.  
  435.     hDocument = GetWindowDocument(window);
  436.     ForgetHandle( & (*hDocument)->fileAlias );
  437.  
  438.     // save the text
  439.  
  440.     if ( ( err = WriteTextFile( pFileSpec, (*hDocument)->we ) ) == noErr )
  441.     {
  442.         SetWTitle( window, pFileSpec->name );
  443.  
  444.         // replace the old window alias (if any) with a new one created from pFileSpec
  445.         NewAlias( nil, pFileSpec, &alias );
  446.  
  447.         // if err, alias will be nil, and it's not fatal, just will make subsequent saves annoying
  448.         (* hDocument)->fileAlias = (Handle) alias;
  449.     }
  450.  
  451.     return err;
  452. }
  453.  
  454.  
  455. OSErr    DoSaveAs( const FSSpec *suggestedTarget, WindowRef window )
  456. {
  457.     StringHandle        hPrompt;
  458.     Str255                defaultName;
  459.     StandardFileReply    reply;
  460.     Point                where = { -1, -1 }; // autocenter's dialog
  461.     OSErr                err;
  462.  
  463.     // get the prompt string for CustomPutFile from a string resource and lock it
  464.     hPrompt = GetString( kPromptStringID );
  465.     HLockHi( (Handle) hPrompt );
  466.  
  467.     // if a suggested target file is provided, use its name as the default name
  468.     if ( suggestedTarget != nil )
  469.     {
  470.         PStringCopy( suggestedTarget->name, defaultName );
  471.         SetDefaultDirectory( suggestedTarget );
  472.     }
  473.     else
  474.     {
  475.         // otherwise use the window title as default name for CustomPutFile
  476.         GetWTitle( window, defaultName );
  477.     }
  478.  
  479.     // put up the standard Save dialog box
  480.     CustomPutFile( *hPrompt, defaultName, &reply, 0, where, nil, GetMySFDialogFilter(), nil, nil, nil );
  481.  
  482.     // unlock the string resource
  483.     HUnlock( (Handle)hPrompt );
  484.  
  485.     // if the user ok'ed the dialog, save the window to the specified file
  486.     if ( reply.sfGood )
  487.         err = SaveWindow( &reply.sfFile, window );
  488.     else
  489.         err = userCanceledErr;
  490.  
  491.     return err;
  492. }
  493.  
  494. OSErr    DoSave( WindowRef window )
  495. {
  496.     FSSpec        spec;
  497.     FSSpecPtr    suggestedTarget = nil;
  498.     Boolean        promptForNewFile = true;
  499.     Boolean        aliasTargetWasChanged;
  500.     OSErr        err;
  501.  
  502.     // resolve the alias associated with this window, if any
  503.  
  504.     if ( (* GetWindowDocument(window) )->fileAlias != nil )
  505.     {
  506.         if ( ( ResolveAlias( nil, (AliasHandle) (* GetWindowDocument(window))->fileAlias, &spec, &aliasTargetWasChanged ) == noErr ) )
  507.         {
  508.             if ( aliasTargetWasChanged )
  509.                 suggestedTarget = &spec;
  510.             else
  511.                 promptForNewFile = false;
  512.         }
  513.     }
  514.  
  515.     // if no file has been previously associated with this window, or if the
  516.     // alias resolution has failed, or if the alias target was changed
  517.     // prompt the user for a new destination
  518.  
  519.     if ( promptForNewFile )
  520.         err = DoSaveAs( suggestedTarget, window );
  521.     else
  522.         err = SaveWindow( &spec, window );
  523.  
  524.     return err;
  525. }
  526.  
  527. static pascal Boolean SaveChangesDialogFilter( DialogRef dialog, EventRecord *event, short *item )
  528. {
  529.     //    map command + D to the "Don't Save" button
  530.     if ( ( event->what == keyDown ) && ( event->modifiers & cmdKey ) && ( ( event->message & charCodeMask ) == 'd' ) )
  531.     {
  532.         //    flash the button briefly
  533.         FlashButton( dialog, kButtonDontSave );
  534.  
  535.         //    fake an event in the button
  536.         *item = kButtonDontSave;
  537.         return true;
  538.     }
  539.  
  540.     //    route everything else to our default handler
  541.     return CallModalFilterProc( GetMyStandardDialogFilter( ), dialog, event, item );
  542. }
  543.  
  544. OSErr DoClose( ClosingOption closing, SavingOption saving, WindowRef window )
  545. {
  546.     Str255        s1, s2;
  547.     short        alertResult;
  548.     OSErr        err;
  549. #ifdef __cplusplus
  550.     static ModalFilterUPP sFilterProc = NewModalFilterProc( SaveChangesDialogFilter );
  551. #else
  552.     static ModalFilterUPP sFilterProc = nil;
  553.     if ( sFilterProc == nil )
  554.     {
  555.         sFilterProc = NewModalFilterProc( SaveChangesDialogFilter );
  556.     }
  557. #endif
  558.  
  559.     // is this window dirty?
  560.     if ( WEGetModCount( GetWindowWE(window) ) > 0 )
  561.     {
  562.         // do we have to ask the user whether to save changes?
  563.  
  564.         if ( saving == savingAsk )
  565.         {
  566.             // prepare the parametric strings to be used in the Save Changes alert box
  567.  
  568.             GetWTitle( window, s1 );
  569.  
  570.             GetIndString( s2, kClosingQuittingStringsID, 1 + closing );
  571.             ParamText( s1, s2, nil, nil );
  572.  
  573.             // put up the Save Changes? alert box
  574.  
  575.             SetCursor( &qd.arrow );
  576.  
  577.             alertResult = Alert( kAlertSaveChanges, sFilterProc );
  578.  
  579.             // exit if the user canceled the alert box
  580.  
  581.             if ( alertResult == kButtonCancel )
  582.                 return userCanceledErr;
  583.  
  584.             if ( alertResult == kButtonSave )
  585.                 saving = savingYes;
  586.             else
  587.                 saving = savingNo;
  588.         }
  589.  
  590.         if ( saving == savingYes )
  591.         {
  592.             if ( ( err = DoSave( window ) ) != noErr )
  593.                 return err;
  594.         }
  595.     }
  596.  
  597.     // destroy the window
  598.     DestroyWindow( window );
  599.  
  600.     return noErr;
  601. }
  602.  
  603. OSErr DoQuit( SavingOption saving )
  604. {
  605.     WindowRef window;
  606.     OSErr err;
  607.  
  608.     // close all windows
  609.     do
  610.     {
  611.         if ( ( window = FrontWindow( ) ) != nil )
  612.         {
  613.             if ( ( err = DoClose( closingApplication, saving, window ) ) != noErr )
  614.                 return err;
  615.         }
  616.     } while ( window != nil );
  617.  
  618.     // set a flag so we drop out of the event loop
  619.     gExiting = true;
  620.  
  621.     return noErr;
  622. }
  623.  
  624. void DoAppleChoice( short menuItem )
  625. {
  626.     if ( menuItem == kItemAbout )
  627.         DoAboutBox( kDialogAboutBox );
  628.     else
  629.         DoDeskAcc( menuItem );
  630. }
  631.  
  632. void DoFileChoice( short menuItem )
  633. {
  634.     WindowRef window = FrontWindow();
  635.  
  636.     switch( menuItem )
  637.     {
  638.         case kItemNew:
  639.             DoNew( );
  640.             break;
  641.  
  642.         case kItemOpen:
  643.             DoOpen( );
  644.             break;
  645.  
  646.         case kItemClose:
  647.             DoClose( closingWindow, savingAsk, window );
  648.             break;
  649.  
  650.         case kItemSave:
  651.             DoSave( window );
  652.             break;
  653.  
  654.         case kItemSaveAs:
  655.             DoSaveAs( nil, window );
  656.             break;
  657.  
  658.         case kItemQuit:
  659.             DoQuit( savingAsk );
  660.             break;
  661.     }
  662. }
  663.  
  664. void DoEditChoice( short menuItem )
  665. {
  666.     WindowRef window;
  667.     WEReference we;
  668.  
  669.     // do nothing is no window is active
  670.     if ( ( window = FrontWindow( ) ) == nil )
  671.         return;
  672.     we = GetWindowWE(window);
  673.  
  674.     switch ( menuItem )
  675.     {
  676.         case kItemUndo:
  677.             WEUndo( we );
  678.             break;
  679.  
  680.         case kItemCut:
  681.             WECut( we);
  682.  
  683.         case  kItemCopy:
  684.             WECopy( we );
  685.             break;
  686.  
  687.         case kItemPaste:
  688.             WEPaste( we );
  689.             break;
  690.  
  691.         case kItemClear:
  692.             WEDelete( we );
  693.             break;
  694.  
  695.         case kItemSelectAll:
  696.             WESetSelection( 0, LONG_MAX, we );
  697.             break;
  698.     }
  699. }
  700.  
  701. void DoFontChoice( short menuItem, EventModifiers modifiers )
  702. {
  703.     WindowRef        window;
  704.     Str255            fontName;
  705.     WEStyleMode        mode;
  706.     TextStyle        ts;
  707.  
  708.     if ( ( window = FrontWindow( ) ) != nil )
  709.     {
  710.         GetMenuItemText( GetMenuHandle( kMenuFont ), menuItem, fontName );
  711.         GetFNum( fontName, &ts.tsFont );
  712.         mode = ( modifiers & optionKey ) ? weDoFont : ( weDoFont + weDoPreserveScript + weDoExtractSubscript ) ;
  713.         WESetStyle( mode, &ts, GetWindowWE( window ) );
  714.     }
  715. }
  716.  
  717. void DoSizeChoice( short menuItem )
  718. {
  719.     WindowRef        window;
  720.     Str255            sizeString;
  721.     long            size;
  722.     WEStyleMode        mode;
  723.     TextStyle        ts;
  724.  
  725.     if ( ( window = FrontWindow ( ) ) != nil )
  726.     {
  727.         if ( menuItem <= kItemLastSize )
  728.         {
  729.             GetMenuItemText( GetMenuHandle( kMenuSize ), menuItem, sizeString );
  730.             StringToNum( sizeString, &size );
  731.             mode = weDoSize;
  732.             ts.tsSize = size;
  733.         }
  734.         else if ( menuItem == kItemSmaller )
  735.         {
  736.             mode = weDoAddSize;
  737.             ts.tsSize = -1;
  738.         }
  739.         else if ( menuItem == kItemLarger )
  740.         {
  741.             mode = weDoAddSize;
  742.             ts.tsSize = +1;
  743.         }
  744.  
  745.         WESetStyle( mode, &ts, GetWindowWE( window ) );
  746.     }
  747. }
  748.  
  749. void DoStyleChoice( short menuItem )
  750. {
  751.     WindowRef window;
  752.     TextStyle ts;
  753.  
  754.     if ( ( window = FrontWindow( ) ) != nil )
  755.     {
  756.         switch( menuItem )
  757.         {
  758.             case kItemPlainText:
  759.                 ts.tsFace = normal;
  760.                 break;
  761.  
  762.             case kItemBold:
  763.             case kItemItalic:
  764.             case kItemUnderline:
  765.             case kItemOutline:
  766.             case kItemShadow:
  767.             case kItemCondensed:
  768.             case kItemExtended:
  769.                 ts.tsFace = 1 << ( menuItem - kItemBold );
  770.                 break;
  771.         }
  772.  
  773.         WESetStyle( weDoFace + weDoToggleFace, &ts, GetWindowWE( window ) );
  774.     }
  775. }
  776.  
  777. void DoColorChoice( short menuItem )
  778. {
  779.     WindowRef            window;
  780.     short                i;
  781.     TextStyle            ts;
  782.  
  783.     // do nothing if there is no front window
  784.     if ( ( window = FrontWindow( ) ) == nil )
  785.         return;
  786.  
  787.     // find the color corresponding to the chosen menu item
  788.     for ( i = (*sColors)->numEntries - 1; i >= 0; i-- )
  789.     {
  790.         if ( (*sColors)->mcEntryRecs[i].mctItem == menuItem )
  791.         {
  792.             ts.tsColor = (*sColors)->mcEntryRecs[i].mctRGB2;
  793.             WESetStyle( weDoColor, &ts, GetWindowWE(window) );
  794.         }
  795.     }
  796. }
  797.  
  798. void    DoAlignChoice( short menuItem )
  799. {
  800.     WindowRef window;
  801.     WEAlignment alignment;
  802.  
  803.     if ( ( window = FrontWindow( ) ) != nil )
  804.     {
  805.         switch( menuItem )
  806.         {
  807.             case kItemAlignDefault:
  808.                 alignment = weFlushDefault;
  809.                 break;
  810.  
  811.             case kItemAlignLeft:
  812.                 alignment = weFlushLeft;
  813.                 break;
  814.  
  815.             case kItemCenter:
  816.                 alignment = weCenter;
  817.                 break;
  818.  
  819.             case kItemAlignRight:
  820.                 alignment = weFlushRight;
  821.                 break;
  822.  
  823.             case kItemJustify:
  824.                 alignment = weJustify;
  825.                 break;
  826.         }
  827.  
  828.         // set the alignment mode (this automatically redraws the text)
  829.         WESetAlignment( alignment, GetWindowWE(window) );
  830.     }
  831. }
  832.  
  833.  
  834. void    DoFeatureChoice( short menuItem )
  835. {
  836.     WindowRef window;
  837.     WEReference we;
  838.     short feature;
  839.  
  840.     if ( ( window = FrontWindow( ) ) == nil )
  841.         return;
  842.  
  843.     we = GetWindowWE(window);
  844.  
  845.     if ( menuItem == kItemTabHooks )
  846.     {
  847.         // install or remove our custom tab hooks
  848.  
  849.         if ( ! WEIsTabHooks( we ) )
  850.         {
  851.             // left-align the text (the hooks only work with left-aligned text )
  852.             WESetAlignment( weFlushLeft, we );
  853.  
  854.             // install tab hooks
  855.             WEInstallTabHooks( we );
  856.         }
  857.         else
  858.         {
  859.             // remove tab hooks
  860.             WERemoveTabHooks( we );
  861.         }
  862.  
  863.         // turn the cursor into a wristwatch
  864.         SetCursor( * GetCursor( watchCursor ) );
  865.  
  866.         // recalculate link breaks and redraw the text
  867.         WECalText( we );
  868.         WEUpdate( nil, we );
  869.     }
  870.     else
  871.     {
  872.         switch ( menuItem )
  873.         {
  874.             case kItemAutoScroll:
  875.                 feature = weFAutoScroll;
  876.                 break;
  877.  
  878.             case kItemOutlineHilite:
  879.                 feature = weFOutlineHilite;
  880.                 break;
  881.  
  882.             case kItemReadOnly:
  883.                 feature = weFReadOnly;
  884.                 break;
  885.  
  886.             case kItemIntCutAndPaste:
  887.                 feature = weFIntCutAndPaste;
  888.                 break;
  889.  
  890.             case kItemDragAndDrop:
  891.                 feature = weFDragAndDrop;
  892.                 break;
  893.  
  894.             case kItemOffscreenDrawing:
  895.                 feature = weFDrawOffscreen;
  896.                 break;
  897.         }
  898.  
  899.         // toggle the specified feature
  900.         WEFeatureFlag( feature, weBitToggle, we );
  901.     }
  902. }
  903.  
  904. void DoMenuChoice( long menuChoice, EventModifiers modifiers )
  905. {
  906.     short menuID, menuItem;
  907.  
  908.     // extract menu ID and menu item from menuChoice
  909.  
  910.     menuID = HiWrd( menuChoice );
  911.     menuItem = LoWrd( menuChoice );
  912.  
  913.     // dispatch on menuID
  914.  
  915.     switch( menuID )
  916.     {
  917.         case kMenuApple:
  918.             DoAppleChoice( menuItem );
  919.             break;
  920.  
  921.         case kMenuFile:
  922.             DoFileChoice( menuItem );
  923.             break;
  924.  
  925.         case kMenuEdit:
  926.             DoEditChoice( menuItem );
  927.             break;
  928.  
  929.         case kMenuFont:
  930.             DoFontChoice( menuItem, modifiers );
  931.             break;
  932.  
  933.         case kMenuSize:
  934.             DoSizeChoice( menuItem );
  935.             break;
  936.  
  937.         case kMenuStyle:
  938.             DoStyleChoice( menuItem );
  939.             break;
  940.  
  941.         case kMenuColor:
  942.             DoColorChoice( menuItem );
  943.             break;
  944.  
  945.         case kMenuFeatures:
  946.             DoFeatureChoice( menuItem );
  947.             break;
  948.  
  949.         case kMenuAlignment:
  950.             DoAlignChoice( menuItem );
  951.             break;
  952.     }
  953.     HiliteMenu( 0 );
  954. }
  955.  
  956. OSErr    InitializeMenus( void )
  957. {
  958.     OSErr        err = noErr;
  959.  
  960.     // build up the whole menu bar from the 'MBAR' resource
  961.  
  962.     SetMenuBar( GetNewMBar( kMenuBarID ) );
  963.  
  964.     // add names to the apple and Font menus
  965.  
  966.     AppendResMenu( GetMenuHandle( kMenuApple ), kTypeDeskAccessory );
  967.     AppendResMenu( GetMenuHandle( kMenuFont ), kTypeFont );
  968.  
  969.     // insert the alignment subment into the hierarchical portion of the menu list
  970.     InsertMenu( GetMenu( kMenuAlignment), -1 );
  971.  
  972.     // disable the "Drag and Drop Editing" item in the Features menu once and for all
  973.     // if the Drag Manager isn't available
  974.  
  975.     if ( ! gHasDragAndDrop )
  976.         DisableItem( GetMenuHandle( kMenuFeatures ), kItemDragAndDrop );
  977.  
  978.     // load the menu color table for the color menu
  979.  
  980.     sColors = (MenuCRsrcHandle)GetResource( kTypeMenuColorTable, kMenuColor );
  981.     err = ResError();
  982.     if ( err != noErr )
  983.         return err;
  984.     HNoPurge( (Handle)sColors );
  985.  
  986.     // draw the menu bar
  987.  
  988.     DrawMenuBar();
  989.  
  990.     return err;
  991. }